/*
* INSANE - Interactive Structural Analysis Environment
*
* Copyright (C) 2003-2004
* Universidade Federal de Minas Gerais
* Escola de Engenharia
* Departamento de Engenharia de Estruturas
*
* Author's email : insane@dees.ufmg.br
* Author's Website : http://www.dees.ufmg.br/insane
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
package br.ufmg.dees.insane.model.xfemModel.enrichmentItem;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;

import br.ufmg.dees.insane.model.xfemModel.XFemModel;
import br.ufmg.dees.insane.model.xfemModel.crackGrowthDirectionLaw.CrackGrowthDirectionLaw;
import br.ufmg.dees.insane.model.xfemModel.crackGrowthDirectionLaw.NonLocalPrincipalStressDirection;
import br.ufmg.dees.insane.model.xfemModel.crackGrowthIncrementLaw.BoundaryElementIncrement;
import br.ufmg.dees.insane.model.xfemModel.crackGrowthIncrementLaw.CrackGrowthIncrementLaw;
import br.ufmg.dees.insane.model.xfemModel.enrichmentDetector.SplitElementDetect;
import br.ufmg.dees.insane.model.xfemModel.geometryEntity.PiecewiseLinear;
import br.ufmg.dees.insane.model.xfemModel.geometryEntity.Vertex;
import br.ufmg.dees.insane.model.xfemModel.xfemElement.XFEMElement;
import br.ufmg.dees.insane.util.IPoint3d;
import br.ufmg.dees.insane.util.xfem.Segment;

/**
 * @author Kelson Wolff
 *
 */
public class CrackInterior extends EnrichmentItem {
	
	/**
	 * Comment for <code>serialVersionUID</code>
	 */
	private static final long serialVersionUID = 1L;
	
	private List<CrackTip> myTips;
//	private double a;
	private boolean isBranchedCrack;
//	private CrackInterior myMasterCrack;

	/**
	 * 
	 */
	public CrackInterior() {
		super();
		// TODO Auto-generated constructor stub
		this.myEnrDetector = new SplitElementDetect();
		this.myGeometry = new PiecewiseLinear();
		this.myTips = new ArrayList<CrackTip>();
	}

	/**
	 * @return Returns the myTips.
	 */
	public List<CrackTip> getMyTips() {
		return myTips;
	}

	/**
	 * @param myTips The myTips to set.
	 */
	public void setMyTips(List<CrackTip> myTips) {
		this.myTips = myTips;
		ListIterator tips = myTips.listIterator();
		while(tips.hasNext()){
			CrackTip tip = (CrackTip) tips.next();
			tip.setMyCrackInterior(this);
		}
	}
	
	/**
	 * 
	 * @param tip
	 */
	public void setMyTips(CrackTip tip){
		this.myTips.add(tip);
		tip.setMyCrackInterior(this);
	}

	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.model.xfemModel.enrichmentItem.EnrichmentItem#resolveLinearDependency()
	 */
	@Override
	public void resolveLinearDependency() {
		// TODO Auto-generated method stub

	}
	
	/**
	 *
	 */
	public void resolveConflictsInNodalEnrichment(){
		
	}

	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.model.xfemModel.enrichmentItem.EnrichmentItem#updateMyGeometry()
	 */
	@Override
	public void updateMyGeometry(NonLocalPrincipalStressDirection dirLaw, BoundaryElementIncrement incLaw) {
		// TODO Auto-generated method stub

	}
	
	@Override
	public void updateMyGeometry(CrackGrowthDirectionLaw dirLaw, CrackGrowthIncrementLaw incLaw) {
		// TODO Auto-generated method stub
		
	}
	
	/**
	 * Inserts new tips into list of vertices correctly when crack grow.
	 * Code's convention:
	 * 	- Crack with two tips : [left tip right tip]
	 * 	- Crack with one tip  : [right tip]
	 */
	public void updateMyGeometry(){
		Vertex tip;
		Segment s, seg;
		PiecewiseLinear geo = (PiecewiseLinear) this.getMyGeometry();
		
		//CrackInterior with ONE tip
		if(this.getMyTips().size() == 1){
			tip = this.getMyTips().get(0).getTip();
			s = this.getMyTips().get(0).getTipSegment();
			seg = new Segment(s.getFirstPoint(),s.getSecondPoint());
			geo.insertNewSegmentAtBack(seg);
			geo.insertNewVertexAtBack(tip);
		}
		//CrackInterior with TWO tips
		else if(this.getMyTips().size() == 2){
			for(int i=0; i<this.getMyTips().size(); i++){
				tip = this.getMyTips().get(i).getTip();
				s = this.getMyTips().get(i).getTipSegment();
				// first tip, i.e., left tip !!!
				if(i == 0){
					geo.insertNewVertexInFront(tip);
					seg = new Segment(s.getFirstPoint(),s.getSecondPoint());
					geo.insertNewSegmentInFront(seg);
				}
				// second tip, i.e., right tip !!!
				else if(i == 1){
					geo.insertNewVertexAtBack(tip);
					seg = new Segment(s.getFirstPoint(),s.getSecondPoint());
					geo.insertNewSegmentAtBack(seg);
				}
			}
		}
	}


	/* (non-Javadoc)
	 * @see br.ufmg.dees.insane.model.xfemModel.enrichmentItem.EnrichmentItem#updateEnrichment()
	 */
	@Override
	public void updateEnrichment(XFemModel model) {
		// TODO Auto-generated method stub

	}
	
	/**
	 * Finds the exact position of myTips (the tips that belong to this
	 * CrackInterior) inside the mesh. Tests if each tip is inside an 
	 * element or on his edges. Then, sets the interaction that exists
	 * between each tip and interacted element inside both objects the
	 * tip and the interacted element.
	 */
	public void treatMeshGeoInteractionForMyTips(){
		List<XFEMElement> interactedElems = this.getInteractedElements();
		ListIterator tips = this.getMyTips().listIterator();
		CrackTip tip;
		
		while(tips.hasNext()){
			XFEMElement tipElem = null;
			// Verifies the crack tip is inside the interacted element.
			tip = (CrackTip) tips.next();
			for(int i=0; i<interactedElems.size(); i++){
				if(tip.interactsWith((XFEMElement)interactedElems.get(i))){
					tipElem = (XFEMElement) interactedElems.get(i);
					i = interactedElems.size();
				}
			}
			// Verifies the crack tip is inside one interacted element neighbor.
			if(tipElem == null){
				List<XFEMElement> allNeighbors = new ArrayList<XFEMElement>();
				ListIterator interacElms = interactedElems.listIterator();
				while(interacElms.hasNext()){
					XFEMElement interacElm = (XFEMElement) interacElms.next();
					allNeighbors.addAll(interacElm.getMyNeighbors());
				}
				Collection<XFEMElement> neighbors = new HashSet<XFEMElement>(allNeighbors);
				List<XFEMElement> interactedNeighbors = new ArrayList<XFEMElement>(neighbors);
				for(int j=0; j<interactedNeighbors.size(); j++){
					XFEMElement e = (XFEMElement) interactedNeighbors.get(j);
					if(tip.interactsWith(e)){
						tipElem = e;
						j = interactedNeighbors.size();
					}
				}
			}
			// Verifies the crack tip touch interacted element edges.
			if(tipElem == null){
	
				tip.setOnElementEdge(true);
				
				double x = tip.getTip().getCoordinates(0);
				double y = tip.getTip().getCoordinates(1);
				IPoint3d p = new IPoint3d(x,y);
				for(int k=0; k<interactedElems.size(); k++){
					if(interactedElems.get(k).isOnEdge(p)){
						tipElem = (XFEMElement) interactedElems.get(k);
						k = interactedElems.size();
					}
				}
			}
			// Verifies the crack tip touch interacted element edges neighbor.
			if(tipElem == null){
				
				double x = tip.getTip().getCoordinates(0);
				double y = tip.getTip().getCoordinates(1);
				IPoint3d p = new IPoint3d(x,y);
				
				boolean found = false;
				
				List<XFEMElement> allNeighbors = new ArrayList<XFEMElement>();
				ListIterator interacElms = interactedElems.listIterator();
				while(interacElms.hasNext()){
					XFEMElement interacElm = (XFEMElement) interacElms.next();
					allNeighbors.addAll(interacElm.getMyNeighbors());
				}
				Collection<XFEMElement> neighbors = new HashSet<XFEMElement>(allNeighbors);
				List<XFEMElement> interactedNeighbors = new ArrayList<XFEMElement>(neighbors);
				ListIterator interacNeigh = interactedNeighbors.listIterator();
				while((!found) && (interacNeigh.hasNext())){
					XFEMElement e = (XFEMElement) interacNeigh.next();
					if(e.isOnEdge(p)){
						tipElem = e;
						found = true;
					}
				}
			}
			
			tipElem.isEnrichedWith(tip);
			tip.setInteractedElements(tipElem);
		}
	}
	
	/**
	 * 
	 * @return
	 */
	public double getCrackLength(){
		return 0;
	}
	
	/**
	 *
	 */
	public void setCrackLength(){
		
	}
	
	/**
	 * 
	 * @return
	 */
	public boolean IsABranchedCrack(){
		return this.isBranchedCrack;
	}
	
	/**
	 *
	 */
	public void treatJunctionEnrichment(){
		
	}
	
	/**
	 * Check if provided element interacts with this enrichment item or not. If so, 
	 * insert this element into the list of each enrichment item.
	 * @param e The provided XFEMElement e.
	 */
	public void treatMeshGeoInteraction(XFEMElement e){
		if(this.interactsWith(e)){
			e.isEnrichedWith(this);
			this.setInteractedElements(e);
			ListIterator tips = this.getMyTips().listIterator();
			while(tips.hasNext()){
				CrackTip tip = (CrackTip) tips.next();
				tip.setInteractedElements(e);
			}
		}
	}

}
